package biz

import (
	"context"
	"errors"
	"google.golang.org/protobuf/types/known/emptypb"
	"time"

	v1 "kratosEtcdWatcher/api/lottery/v1"

	"fmt"
	"github.com/go-kratos/kratos/v2/log"
)

const (
	LotteryTableName = "lottery"
)

type Lottery struct {
	Id         uint32    `gorm:"column:id" json:"id"`
	ActivityId uint32    `gorm:"column:activity_id" json:"activityId"`          // 活动id，唯一索引
	TotalLimit uint32    `gorm:"column:total_limit" json:"totalLimit"`          // 总次数限制
	DailyLimit uint32    `gorm:"column:daily_limit" json:"dailyLimit"`          // 每日次数限制
	CreateAt   time.Time `gorm:"column:create_at;default:null" json:"createAt"` //  创建时间
	UpdateAt   time.Time `gorm:"column:update_at;default:null" json:"updateAt"` //  更新时间
}

func (l *Lottery) TableName() string {
	return LotteryTableName
}

type LotteryRepo interface {
	// Upsert方法只有B端管理后台用，调用频率不高
	UpsertLottery(context.Context, *Lottery) error
	// GetAllLotteriesFromDBOrRedis 只有在更新数据、本地缓存没有数据的时候才会用到，调用频率不高
	GetAllLotteriesFromDBOrRedis(ctx context.Context) ([]Lottery, error)
	// 只有在更新数据、本地缓存没有数据的时候才会用到，调用频率不高
	GetLotteryByActivityId(ctx context.Context, lotteryId uint32) (*Lottery, error)
}

type LotteryUsecase struct {
	repo            LotteryRepo
	log             *log.Helper
	etcdWatchOrigin GlobalLotteryInterfaceOrigin // 使用原生的方式实现的etcdWatch
	etcdWatchKratos GlobalLotteryInterfaceKratos // 使用kratos封装好的etcdWatch
}

func NewLotteryUsecase(repo LotteryRepo, logger log.Logger, etcdWatchOrigin GlobalLotteryInterfaceOrigin, etcdWatchKratos GlobalLotteryInterfaceKratos) *LotteryUsecase {

	lU := &LotteryUsecase{
		repo:            repo,
		log:             log.NewHelper(logger),
		etcdWatchOrigin: etcdWatchOrigin,
		etcdWatchKratos: etcdWatchKratos,
	}

	return lU
}

func (uc *LotteryUsecase) UpsertLottery(ctx context.Context, req *v1.UpsertLotteryRequest) (*emptypb.Empty, error) {

	reply := &emptypb.Empty{}

	lotteryModel := &Lottery{
		ActivityId: req.ActivityId,
		TotalLimit: req.TotalLimit,
		DailyLimit: req.DailyLimit,
	}

	if err := uc.repo.UpsertLottery(ctx, lotteryModel); err != nil {
		return nil, err
	}

	return reply, nil
}

func (uc *LotteryUsecase) GetLotteryByActivityId(ctx context.Context, req *v1.GetLotteryByActivityIdReq) (*v1.GetLotteryByActivityIdReply, error) {

	// Notice 从本地内存获取
	// 1、使用原生的 etcdWatch，使用 sync.Map 存储
	//lottery, err := uc.etcdWatchOrigin.GetLotteryByActivityIdFromSyncMap(ctx, req.ActivityId, uc.repo.GetLotteryByActivityId)
	//if err != nil {
	//	return nil, err
	//}
	//reply := &v1.GetLotteryByActivityIdReply{
	//	ActivityId: lottery.ActivityId,
	//	TotalLimit: lottery.TotalLimit,
	//	DailyLimit: lottery.DailyLimit,
	//}

	// 2、使用kratos封装好的 etcdWatch
	allActivitiesMap, err := uc.etcdWatchKratos.GetAllActivitiesLotteriesKratos(ctx, uc.repo.GetAllLotteriesFromDBOrRedis)
	if err != nil {
		return nil, err
	}
	fmt.Println("allActivitiesMap: ", allActivitiesMap)
	ret, ok := allActivitiesMap[req.ActivityId]
	if !ok {
		return nil, errors.New(fmt.Sprintf("该activityId %v 没有对应的数据!", req.ActivityId))
	}
	reply := &v1.GetLotteryByActivityIdReply{
		ActivityId: ret.ActivityId,
		TotalLimit: ret.TotalLimit,
		DailyLimit: ret.DailyLimit,
	}

	return reply, nil
}
